package com.kuangstudy.config.redis.config;

import io.rebloom.client.ClusterClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.HostAndPort;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
public class JedisUtils {

    public static String REDIS_CLUSTER = "47.115.94.78:6379";
    public static String REDIS_PASSWORD = "mkxiaoer1986.";
    private static final Lock lock = new ReentrantLock();

    public static void main(String[] args) {
        JedisBloomFilterProxy bloomFilterRedisProxy = new JedisUtils().getBloomFilterRedisProxy();
        bloomFilterRedisProxy.createFilter("room:filter",100,0.01);
    }

    /**
     * redis-server需 4.x版本及以上
     *
     * @return
     */
    public JedisBloomFilterProxy getBloomFilterRedisProxy() {
        return new JedisBloomFilterProxy(REDIS_CLUSTER, "", REDIS_PASSWORD);
    }


    /**
     * 概述：布隆过滤器 redis的proxy
     *
     * @author maoyuanming
     * @version v1.0.0
     * @date 2019-10-28
     */
    public class JedisBloomFilterProxy {

        private ClusterClient clusterClient = null;

        private String prefix = "";

        public JedisBloomFilterProxy(String cluster, String prefix, String password) {
            if (clusterClient == null) {
                clusterClient = getBloomFilterClusterClient(cluster, password);
            }
            this.prefix = prefix;
        }

        public boolean createFilter(final String name, final long initCapacity, final double errorRate) {
            return clusterClient.createFilter(prefix + name, initCapacity, errorRate);
        }

        public boolean[] addMulti(final String name, final byte[]... values) {
            return clusterClient.addMulti(prefix + name, values);
        }

        public boolean[] addMulti(final String name, final String... values) {
            return clusterClient.addMulti(prefix + name, values);
        }

        public boolean add(final String name, final String value) {
            return clusterClient.add(prefix + name, value);
        }

        public boolean add(final String name, final byte[] value) {
            return clusterClient.add(prefix + name, value);
        }

        public boolean exists(final String name, final String value) {
            return clusterClient.add(prefix + name, value);
        }

        public boolean exists(final String name, final byte[] value) {
            return clusterClient.add(prefix + name, value);
        }

        public boolean delete(final String name) {
            return clusterClient.delete(prefix + name);
        }

        public boolean[] existsMulti(final String name, final byte[] value) {
            return clusterClient.existsMulti(prefix + name, value);
        }

        public boolean[] existsMulti(final String name, final String... values) {
            return clusterClient.existsMulti(prefix + name, values);
        }

        public long expire(final String key, final int seconds) {
            return clusterClient.expire(prefix + key, seconds);
        }

        public long expireAt(final String key, final long unixTime) {
            return clusterClient.expireAt(prefix + key, unixTime);
        }

        public long ttl(final String key) {
            return clusterClient.ttl(prefix + key);
        }

        /**
         * key是否存在
         *
         * @param key
         * @return
         */
        public boolean exists(final String key) {
            return clusterClient.exists(prefix + key);
        }

        /**
         * 获取布隆过滤器的redis cluster client
         *
         * @return
         */
        private ClusterClient getBloomFilterClusterClient(String cluster, String password) {
            if (clusterClient == null) {
                initClusterClient(cluster, password);
            }
            return clusterClient;
        }

        /**
         * 初始化
         *
         * @param clusterNode
         * @param password
         * @return
         */
        private ClusterClient initClusterClient(String clusterNode, String password) {
            if (clusterClient == null) {
                log.debug("Create bloom filter client connection pool");
                lock.lock();
                try {
                    if (clusterClient == null) {
                        GenericObjectPoolConfig config = new GenericObjectPoolConfig();
                        config.setMaxTotal(300);    // 最大连接数
                        config.setMaxIdle(100);        // 池中保留的最大空闲连接数
                        config.setMinIdle(100);        // 池中保留的最小空闲连接数
                        config.setMaxWaitMillis(5 * 1000); // 最大等待时间
                        config.setTestWhileIdle(true);
                        config.setTestOnBorrow(true);
                        clusterClient = new ClusterClient(getHostAndPort(clusterNode), 300 * 1000, 300 * 1000, 10, password, config);// 创建REDIS集群
                    }
                } finally {
                    lock.unlock();
                }
            } else {
                log.debug("Use bloom filter client connection pool");
            }
            return clusterClient;
        }

        /**
         * 调用此方法会直接与redis服务端断连。非本身服务关闭时避免调用
         */
        public void close() {
            clusterClient.close();
        }
    }

    /**
     * 概述：处理集群连接地址
     *
     * @param clusterNode
     */
    public static Set<HostAndPort> getHostAndPort(String clusterNode) {
        Set<HostAndPort> setList = new HashSet<HostAndPort>();
        if (clusterNode != null) {
            String[] hostArr = ProxyUtils.getSplit(clusterNode, ",");
            if (hostArr == null) {
                return setList;
            }
            String[] hostAdd = null;
            for (int i = 0; i < hostArr.length; i++) {
                hostAdd = ProxyUtils.getSplit(hostArr[i], ":");
                if (hostAdd == null || hostAdd.length != 2) {
                    continue;
                }
                String[] hosts = ProxyUtils.getSplit(hostAdd[0], "/");
                String[] ports = ProxyUtils.getSplit(hostAdd[1], "/");
                String host = hosts[0];
                if (hosts.length == 2) {
                    host = hosts[1];
                    IPMaps.setIPMap(hosts[0], hosts[1]);
                } else {
                    IPMaps.setIPMap(hosts[0], hosts[0]);
                }
                setList.add(new HostAndPort(host, Integer.valueOf(ports[0])));
            }
        }
        return setList;
    }

}

